﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ParallelRuntimeLibrary.Internal
{
    public sealed class Waiter : WaitHandle
    {
        private int mState;
        private bool mDisposed;

        /*/////////////////////////////////////////////////////////////////////////////////*/

        public bool IsSet
        {
            get
            {
                lock (this)
                return (this.mState == 1);
            }
        }

        /*/////////////////////////////////////////////////////////////////////////////////*/

        public Waiter()
        {
            this.mState = 0;
        }

        private void ThrowIfDisposed()
        {
            if (this.mDisposed)
            {
                throw new ObjectDisposedException("CountdownEvent");
            }
        }

        public void Dispose()
        {
            this.mDisposed = true;
            base.Dispose(true);
        }

        public void Reset()
        {
            ThrowIfDisposed();
            lock (this)
            {
                mState = 0;
            }
        }

        public void Set()
        {
            ThrowIfDisposed();
            lock (this)
            {
                mState = 1;
            }
        }


        public override bool WaitOne()
        {
            return WaitOne(-1);
        }

        public override bool WaitOne(TimeSpan timeout)
        {
            long totalMilliseconds = (long)timeout.TotalMilliseconds;

            if ((totalMilliseconds < -1L) || (totalMilliseconds > int.MaxValue))
                throw new ArgumentOutOfRangeException("timeout");

            return this.WaitOne((int)totalMilliseconds);
        }

        public override bool WaitOne(int millisecondsTimeout)
        {
            return WaitOne(millisecondsTimeout, true);
        }

        public override bool WaitOne(TimeSpan timeout, bool exitContext)
        {
            long totalMilliseconds = (long)timeout.TotalMilliseconds;

            if ((totalMilliseconds < -1L) || (totalMilliseconds > int.MaxValue))
                throw new ArgumentOutOfRangeException("timeout");

            return WaitOne((int)totalMilliseconds, exitContext);
        }

        public override bool WaitOne(int millisecondsTimeout, bool exitContext)
        {
            SpinWait SW = new SpinWait();
            DateTime dt = DateTime.Now;
            do
            {

                if (IsSet)
                    return true;
                else
                {
                    if (millisecondsTimeout == -1)
                        SW.SpinOnce();
                    else
                    {
                        TimeSpan tmp = DateTime.Now - dt;
                        if (tmp.TotalMilliseconds >= millisecondsTimeout) return false;
                        SW.SpinOnce();
                    }
                }

            } while (true);

        }
    }
}
